#pragma once

#include <vector>
#include <map>

#include "Code.h"
#include "TypeDef.h"

namespace FlooP
{
	class Scope;

	class Object
	{
		public:
		
		enum Type
		{
			NUMBER,
			STRING
		};

		virtual Type type () const = 0;
	};

	class Number : public Object
	{
		public:

		Number (uint32_t val);

		void set (uint32_t val);
		uint32_t val () const;

		Type type () const;

		private:

		uint32_t m_val;
	};

	class String : public Object
	{
		public:

		String (const std::string& text);

		void set (const std::string& text);
		const std::string& text () const;

		Type type () const;

		private:

		std::string m_text;
	};

	class Procedure
	{
		public:

		Procedure (const std::string& name);
		Procedure (const std::string& name, const std::vector<std::string>& args);

		const std::string& name () const;
		const std::vector<std::string>& args () const;
		std::shared_ptr<CodeBlock> code () const;
		std::shared_ptr<Scope> scope () const;
		
		uint32_t get_block_end (uint32_t block_num) const;

		void add_block (uint32_t block_num);
		void set_block_end (uint32_t block_num, uint32_t index);

		void fix_abort_quit ();

		void set_scope (std::shared_ptr<Scope> scope);

		private:

		const std::string m_name;
		const std::vector<std::string> m_args;

		// Holds a vector of blocks and their corresponding end code indices
		std::vector<std::pair<uint32_t, uint32_t>> m_blocks;

		// Function defines its arguments inside of the scope upon construction.
		std::shared_ptr<Scope>	   m_scope;
		std::shared_ptr<CodeBlock> m_code;
	};
}